/* This module implements the delay functionality and manages the delayed array */

#include "delay.h"

/* this list contains pointers on the delayed processes */
list delayed;

void initialize_delayed(){
  delayed = NULL;
}

/* inserts pcb into the delayed array */
uint32_t insert_delayed(PCB* pcb){
  return linked_list_add(&delayed, pcb);
}

/* checks if any delayed process is to be waken up */
int32_t process_delayed(){
  int32_t failure = 0;
  PCB* pcb;
  list current = delayed, prev = NULL;
  while(current != NULL){
    pcb = (PCB*)current->data;
    // the remaining time for this process is the time that was remaining one time quantum earlier minus the duration of a time quantum 
    int32_t remaining = pcb_get_delay(pcb) - TIME_QUANTUM_IN_MS;
    if(remaining <= 0){ 
      // this process needs to be waken up
      pcb_set_state(pcb, READY_STATE);
      //removes pcb from the delayed list
      if(linked_list_delete_after_prev(&delayed, prev, current, NULL) == FAILURE){
	//the process couldn't be removed. Let's try to process the others anyway but we have to notify the error as well.
	failure = 1;
	continue;
      }
      if(insert_ready_queue(pcb,0) == OUT_OF_MEMORY){//no need to check for rescheduling, it will be done just after
	return OUT_OF_MEMORY;
      }
      if(prev == NULL){
	current = delayed;
	continue;
      }else
	current = prev;
    }else
      pcb_set_delay(pcb, remaining);
    prev = current;
    current = current->next;
  }
  return (!failure?SUCCESS:FAILURE);
}

/* removes the PCB pcb from the delayed array. Returns SUCCESS if success, FAILURE otherwise */
int32_t remove_delayed(PCB* pcb){
  return linked_list_delete(&delayed, pcb, compare_pcb, NULL);
}
